#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "util.h"

#define FALSE 0;
#define TRUE 1;
#define MAXBACKLOG 50

extern int errno; 

int sock_fd;
bool eof_status = FALSE;
//bool end_of_

/**********************************************
 * init
   - port is the number of the port you want the server to be
     started on
   - initializes the connection acception/handling system
   - YOU MUST CALL THIS EXACTLY ONCE (not once per thread,
     but exactly one time, in the main thread of your program)
     BEFORE USING ANY OF THE FUNCTIONS BELOW
   - if init encounters any errors, it will call exit().
************************************************/
void init(int port) { //Modeled after code presented in lecture slides
	
	int bind_ret_val;
	struct sockaddr_in address;
	int enable = TRUE;
	
	sock_fd = socket(AF_INET, SOCK_STREAM, 0);
	
	if (sock_fd < 0) // handles socket failure
    {
      perror ("Error with socket creation.");
      exit (EXIT_FAILURE);
    }

	address.sin_family = AF_INET;
	address.sin_addr.s_addr = INADDR_ANY;
	address.sin_port = htons(port);
	
	// give the port need enable
	setsockopt (sock_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&enable, sizeof(int));
	
	bind_ret_val =  bind (sock_fd, (struct sockaddr*)&address, sizeof(address));
	
	if (bind_ret_val < 0) //handles bind failure
    {
      perror ("Error with socket binding.");
      exit (EXIT_FAILURE);
    }
	
	listen(sock_fd, 5);
		
}

/**********************************************
 * accept_connection - takes no parameters
   - returns a file descriptor for further request processing.
     DO NOT use the file descriptor on your own -- use
     get_request() instead.
   - if the return value is negative, the dispatch thread calling
     accept_connection must exit by calling pthread_exit().
     Upon all dispatch threads exiting: all worker threads should
     exit when the request queue has become emptied, the dispatch
     threads are gone, and their work on current requests has been
     completed.
***********************************************/
int accept_connection(void){
	int len = sizeof(struct sockaddr);
	struct sockaddr_in netclient;
	int retval;
	
	retval = accept(sock_fd, (struct sockaddr*)(&netclient), &len);
	if (retval == -1)
		perror("Failed to accept connection \n");	
	return retval;
}
	

/**********************************************
 * get_request
   - parameters:
      - fd is the file descriptor obtained by accept_connection()
        from where you wish to get a request
      - filename is the location of a character buffer in which
        this function should store the requested filename. (Buffer
        should be of size 1024 bytes.)
   - returns 0 on success, nonzero on failure. You must account
     for failures because some connections might send faulty
     requests. This is a recoverable error - you must not exit
     inside the thread that called get_request. After an error, you
     must NOT use a return_request or return_error function for that
     specific 'connection'.
************************************************/
int get_request(int fd, char *filename) {
	char *badreq;
	badreq = fgets(filename, 1024, (FILE*) fd);
	if (badreq == NULL){
		perror("EOF reached");
		eof_status = TRUE;
		return -1;
		}
	else {
		if (strstr(filename, "//") != NULL)
			return -1;
		else if (strstr(filename, "..") != NULL)
				return -1;
			else return 0;
		}
	
	
}


/**********************************************
 * return_result
   - returns the contents of a file to the requesting client and cleans
     up the connection to the client
   - parameters:
      - fd is the file descriptor obtained by accept_connection()
        to where you wish to return the result of a request
      - content_type is a pointer to a string that indicates the
        type of content being returned. possible types include
        "text/html", "text/plain", "image/gif", "image/jpeg" cor-
        responding to .html, .txt, .gif, .jpg files.
      - buf is a pointer to a memory location where the requested
        file has been read into memory (the heap). return_result
        will use this memory location to return the result to the
        user. (remember to use -D_REENTRANT for CFLAGS.) you may
        safely deallocate the memory after the call to
        return_result (if it will not be cached).
      - numbytes is the number of bytes the file takes up in buf
   - returns 0 on success, nonzero on failure.
************************************************/
//don't know what to do with content type
int return_result(int fd, char *content_type, char *buf, int numbytes){
	bool fail = false;
	
	if (write(fd, buf, numbytes) ==-1){
		perror("Error writing through pipe\n");
		fail = true;
	}
		
	if (close(fd) == -1){
		perror("Failed to close fd\n");
		fail = true;
	}
	
	if (fail == true)
		return -1;
	else
		return 0;
}
		

/**********************************************
 * return_error
   - returns an error message in response to a bad request and cleans
     up the connection to the client
   - parameters:
      - fd is the file descriptor obtained by accept_connection()
        to where you wish to return the error
      - buf is a pointer to the location of the error text
   - returns 0 on success, nonzero on failure.
************************************************/
int return_error(int fd, char *buf){
	perror(buf);
	if(close(fd) == -1){
		perror("Failed to close connection");
		return -1;
	}
	else return 0;
}
